package club.itstudio.itouc.util

import club.itstudio.itouc.config.AdminConfig
import club.itstudio.itouc.config.ElectiveCoursecConfig
import club.itstudio.itouc.config.LessonConfig
import club.itstudio.itouc.core.exception.ITOUCException
import club.itstudio.itouc.core.exception.SessionInvalid
import club.itstudio.itouc.core.util.Encrypt
import club.itstudio.itouc.core.util.mapper
import club.itstudio.itouc.core.util.sha1
import club.itstudio.itouc.core.util.toJson
import club.itstudio.itouc.entity.*
import com.fasterxml.jackson.module.kotlin.readValue
import org.springframework.data.redis.core.HashOperations
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.stereotype.Repository

@Repository
class Redis (val hashOps: HashOperations<String, String, String>,
             val redisTemplate: RedisTemplate<String, String>,
             val ecConfig: ElectiveCoursecConfig,
             val lessonConfig: LessonConfig){
    /**
     * 存取删JwSession
     */
    private val jwSessionKey = "itouc:jwsession"
    fun saveJwSession(jwSession: JwSession) {
        val token = jwSession.token.substring(0, 16)
        val field = token.sha1()
        jwSession.password = Encrypt.encAES(jwSession.password, token)
        val json = toJson(jwSession)
        hashOps.put(jwSessionKey, field, json)
    }
    fun getJwSession(token: String): JwSession{
        if (token.length <= 16 ) throw SessionInvalid()
        val field = token.substring(0, 16).sha1()
        // 如果存在
        if (hashOps.hasKey(jwSessionKey, field)) {
            val session: JwSession = mapper.readValue(hashOps.get(jwSessionKey, field) ?: "")
            // 解密
            session.password = Encrypt.decAES(session.password, token.substring(0, 16))
            session.token = token
            return session
        } else
            throw SessionInvalid(message = "不存在令牌为：${token}的会话")
    }
    fun deleteJwSession(token: String){
        val field = token.substring(0, 16).sha1()
        hashOps.delete(jwSessionKey, field)
    }
    fun hasJwSession(token: String): Boolean {
        val field = token.substring(0, 16).sha1()
        return hashOps.hasKey(jwSessionKey, field)
    }
    fun deleteAllJwSession() {
        redisTemplate.delete(jwSessionKey)
    }

    /**
     * 存取 OUCStudent
     */
    private val oucStudentKey = "itouc:OUCStudent"
    fun saveOUCStudent(oucStudent: OUCStudent): OUCStudent{
        val json = toJson(oucStudent)
        hashOps.put(oucStudentKey, oucStudent.userCode, json)
        return oucStudent
    }
    fun getOUCStudent(userCode: String): OUCStudent {
        if (hashOps.hasKey(oucStudentKey, userCode))
            return mapper.readValue(hashOps.get(oucStudentKey, userCode) ?: "")
        else
            throw ITOUCException(message = "不存在${userCode}的OUCStudent")
    }

    /**
     * 存取专业列表
     */
    val specialtyKey = "itouc:specialty"
    fun saveSpecialtyList(year: String, specialtyList: List<Specialty>): List<Specialty>{
        val json = toJson(specialtyList)
        hashOps.put(specialtyKey, year, json)
        return  specialtyList
    }
    fun getSpecialtyList(year: String): List<Specialty> {
        if (hashOps.hasKey(specialtyKey, year)) {
            val json = hashOps.get(specialtyKey, year) ?: ""
            return mapper.readValue(json)
        }else
            throw ITOUCException(message = "redis不存在${year}的专业列表")
    }

    /**
     * 存取学生课程信息
     */
    val stuCourseKey = "itouc:stuCourse"
    fun saveStuCourse(stuCourseList: List<StuCourse>,
                      userCode: String,
                      year: String,
                      semester: String) {
        val key = "$stuCourseKey:$year:$semester"
        val res = mutableListOf<StuCourse>()
        stuCourseList.forEach {
            if (it.status == "预选中" || it.status == "选中")
                res.add(it)
        }
        hashOps.put(key, userCode, toJson(res))
    }
    fun getStuCourse(userCode: String, year: String, semester: String): List<StuCourse> {
        val key = "$stuCourseKey:$year:$semester"
        if (hashOps.hasKey(key, userCode)) {
            val jsonList = hashOps.get(key, userCode) ?: ""
            return mapper.readValue(jsonList)
        }else throw ITOUCException(message = "不存在学号为$userCode 的课程信息")
    }

    /**
     * 存取课程信息
     */
    val courseKey = "itouc:course"
    fun saveCourseList(courseList: List<Course>,
                       year: String = ecConfig.year,
                       semester: String = ecConfig.semester) {
        val key = "$courseKey:$year:$semester"
        val map = mutableMapOf<String, String>()
        courseList.forEach {
            map[it.classNum] = toJson(it)
        }
        hashOps.putAll(key, map)
    }
    fun getCourseList(classNumList: List<String>,
                      year: String = ecConfig.year,
                      semester: String = ecConfig.semester): List<Course> {
        val key = "$courseKey:$year:$semester"
        val jsonList = hashOps.multiGet(key, classNumList)
        val courseList = mutableListOf<Course>()
        for (index in jsonList.indices) {
            if (jsonList[index] != null) {
                courseList.add(mapper.readValue(jsonList[index]))
            }else throw ITOUCException(message = "不存在选课号为${classNumList[index]}的课程信息")
        }
        return courseList
    }

    /**
     * 存取成绩信息
     */
    val scoreKey = "itouc:score"
    fun saveScore(userCode: String, scoreList: List<CourseScore>) {
        val time = System.currentTimeMillis()
        val map = mapOf(
                "time" to time,
                "scores" to scoreList
        )
        val json = toJson(map)
        hashOps.put(scoreKey, userCode, json)
    }
    fun getScore(userCode: String): Map<String, Any> {
       if (hashOps.hasKey(scoreKey, userCode)) {
           val json = hashOps.get(scoreKey, userCode) ?: ""
           return mapper.readValue(json)
       }else
           throw ITOUCException(message = "不存在${userCode}的成绩")
    }

    /**
     * 存取毕业学分要求
     */
    val requiredCreditKey = "itouc:requiredCredit"
    fun saveRequiredCredit(userCode: String, credits: List<Credit>) {
        val json = toJson(credits)
        hashOps.put(requiredCreditKey, userCode, json)
    }
    fun getRequiredCredit(userCode: String): List<Credit> {
        if(hashOps.hasKey(requiredCreditKey, userCode)) {
            val json = hashOps[requiredCreditKey, userCode] ?: ""
            return mapper.readValue(json) as List<Credit>
        }else
            throw ITOUCException(message = "不存在${userCode}的毕业学分要求")
    }

    /**
     * 存取建议课表
     */
    val planCourseKey = "itouc:planCourse"
    fun savePlanCourse(year: String, specialtyNum: String, courses: List<CourseScore>) {
        val field = "$year-$specialtyNum"
        val json = toJson(courses)
        hashOps.put(planCourseKey, field, json)
    }
    fun getPlanCourse(year: String, specialtyNum: String): List<CourseScore> {
        val field = "$year-$specialtyNum"
        if (hashOps.hasKey(planCourseKey, field)) {
            val json = hashOps[planCourseKey, field] ?: ""
            return mapper.readValue(json)
        }else
            throw ITOUCException(message = "不存在$year $specialtyNum 的建议课表")
    }

    /**
     * 存取锁
     */
    val lockKey = "itouc:task"
    fun saveLock(taskName: String, expire: Long): Boolean {
        return hashOps.putIfAbsent(lockKey, taskName, "$expire")
    }
    fun deleteLock(taskName: String) {
        hashOps.delete(lockKey, taskName)
    }
    fun getAllLock(): Map<String, Long>{
        val taskMap = hashOps.entries(lockKey)
        val result = mutableMapOf<String, Long>()
        taskMap.forEach { (taskName, expire) ->
            result[taskName] = expire.toLong()
        }
        return result
    }

    /**
     * 存取配置信息
     */
    val configKey = "itouc:config"
    val ecConfigField = "electiveCourse"
    fun saveEcConfig(ecConfig: ElectiveCoursecConfig) {
        val config = ElectiveCoursecConfig(ecConfig.year, ecConfig.semester, ecConfig.open,
                ecConfig.refresh, ecConfig.timestamp)
        hashOps.put(configKey, ecConfigField, toJson(config))
    }
    fun getEcConfigStr() = hashOps.get(configKey, ecConfigField) ?: ""

    val lessonConfigField = "lesson"
    fun saveLessonConfig(newConfig: LessonConfig) {
        val config = LessonConfig(newConfig.startDate, newConfig.year, newConfig.semester, newConfig.courseTime,
                newConfig.dateReplaceMap, newConfig.dateHolidaySet, newConfig.timestamp)
        hashOps.put(configKey, lessonConfigField, toJson(config))
    }
    fun getLessonConfigStr() =  hashOps.get(configKey, lessonConfigField) ?: ""

    val adminConfigField = "adminConfig"
    fun saveAdminConfig(adminConfig: AdminConfig) {
        val config = AdminConfig(adminConfig.adminSet, adminConfig.timeStamp)
        hashOps.put(configKey, adminConfigField, toJson(config))
    }
    fun getAdminConfigStr() = hashOps.get(configKey, adminConfigField) ?: ""

    val accessTokenField = "access_token"
    fun saveAccessToken(map: Map<String, Any>) =
        hashOps.put(configKey, accessTokenField, toJson(map))

    fun getAccessToken(): String =
            hashOps[configKey, accessTokenField] ?: ""




}
